package pl.edu.pw.stud.ltrzaska.policy.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.log4j.Logger;

/**
 * Klasa bazowa dla wszystkich obiektow polityki poprawnosci. Zawiera
 * uniwersalne atrybuty.
 * 
 * @author luk
 * 
 */
public abstract class FilesystemObject implements Serializable {
	private static final Logger LOGGER = Logger.getLogger(FilesystemObject.class);

	private static final long serialVersionUID = -7072136835040674196L;

	public static final String EXISTENCE_OBLIGATORY = "obligatory";
	public static final String EXISTENCE_OPTIONAL = "optional";
	public static final String EXISTENCE_FORBIDDEN = "forbidden";
	public static final String EXISTENCE_DEFAULT = EXISTENCE_OPTIONAL;

	protected FilesystemObject parent = null;

	protected String refName;
	protected String inherits;
	protected String name;
	protected String maxSize;
	protected String minSize;
	protected String existence = EXISTENCE_DEFAULT;
	protected String ownerRefName;
	protected String fileExtension;
	protected FilesystemTime createTime;
	protected FilesystemTime updateTime;

	protected String systemProperties;
	protected List<PolicyValidator> additionalValidators = new ArrayList<PolicyValidator>();
	protected Map<String, String> additionalAttributes = new HashMap<String, String>();
	protected Set<String> additionalValidatorsNames = new HashSet<String>();
	protected Person owner;
	
	public Set<String> getAdditionalValidatorsNames() {
		return additionalValidatorsNames;
	}

	public void setAdditionalValidatorsNames(HashSet<String> additionalValidatorsNames) {
		this.additionalValidatorsNames = additionalValidatorsNames;
	}

	public String getOwnerRefName() {
		return ownerRefName;
	}

	public void setOwnerRefName(String ownerRefName) {
		this.ownerRefName = ownerRefName;
	}

	public void addAdditionalAttribtue(String attrName, String attrValue) {
		additionalAttributes.put(attrName, attrValue);
	}

	public Object getAdditionalAttribtue(String attrName) {
		return additionalAttributes.get(attrName);
	}

	public void setSystemProperties(String systemProperties) {
		this.systemProperties = systemProperties;
	}

	public Map<String, String> getAdditionalAttribtues() {
		return additionalAttributes;
	}

	public String getRefname() {
		return refName;
	}

	public void setRefname(String refname) {
		this.refName = refname;
	}

	public String getInherits() {
		return inherits;
	}

	public void setInherits(String inherits) {
		this.inherits = inherits;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMaxSize() {
		return maxSize;
	}

	public void setMaxSize(String maxSize) {
		this.maxSize = maxSize;
	}

	public String getMinSize() {
		return minSize;
	}

	public void setMinSize(String minSize) {
		this.minSize = minSize;
	}

	public String getExistence() {
		return existence;
	}

	public void setExistence(String existence) {
		this.existence = existence;
	}

	public Person getOwner() {
		return owner;
	}

	public void setOwner(Person owner) {
		this.owner = owner;
	}

	public String getFileExtension() {
		return fileExtension;
	}

	public void setFileExtension(String fileExtension) {
		this.fileExtension = fileExtension;
	}

	public FilesystemTime getCreateTime() {
		return createTime;
	}

	public void setCreateTime(FilesystemTime creationTime) {
		this.createTime = creationTime;
	}

	public FilesystemTime getUpdateTime() {
		return updateTime;
	}

	public void setUpdateTime(FilesystemTime updateTime) {
		this.updateTime = updateTime;
	}

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	public void setParent(FilesystemObject policyParentFsObj) {
		this.parent = policyParentFsObj;
	}

	public FilesystemObject getParent() {
		return parent;
	}

	public boolean hasChildren() {
		return false;
	}

	public void setAdditionalValidators(ArrayList<PolicyValidator> additionalValidators) {
		this.additionalValidators = additionalValidators;
	}

	public List<PolicyValidator> getAdditionalValidators() {
		return additionalValidators;
	}

	/**
	 * Znajduje odpowiedniki tego obiektu polityki w wirtualnym systemie plikow.
	 * W przypadku ogolnym, tzn. tej klasy, odpowiednikami sa pliki/katalogi o
	 * dokladnie tej samej nazwie co obiekt polityki.
	 * 
	 * @param parentVirtualFsObj
	 * @return
	 * @throws FileSystemException
	 */
	public List<FileObject> findVirtualFsEquivalents(FileObject parentVirtualFsObj) throws FileSystemException {
		FileObject[] filesysChildren = parentVirtualFsObj.getChildren();

		List<FileObject> result = new ArrayList<FileObject>();
		for (FileObject fo : filesysChildren) {
			String n = fo.getName().getBaseName();
			
			//LOGGER.debug(new StringBuffer("Sprawdzam ").append(this.getRefname()).append(" do fizycznego ").append(n).toString());
			if (n.equals(this.getName())) {
				result.add(fo);
			}
		}
		return result;
	}

	private void addAdditionalValidator(PolicyValidator pv) {
		this.additionalValidators.add(pv);
		this.additionalValidatorsNames.add(pv.getName());
	}

	/**
	 * Umozliwia dziedziczenie atrybutow z obiektu wzorcowego.
	 * 
	 * @param pattern
	 */
	public void inheritAttributes(PatternObject pattern) {
		if (null == this.getName() || this.getName().length() == 0) {
			this.setName(pattern.getName());
		}
		if (null == this.getMinSize() || this.getMinSize().length() == 0) {

			this.setMinSize(pattern.getMinSize());
		}
		if (null == this.getMaxSize() || this.getMaxSize().length() == 0) {
			this.setMaxSize(pattern.getMaxSize());
		}
		if (null == this.getCreateTime()) {
			this.setCreateTime(pattern.getCreateTime());
		}
		if (null == this.getUpdateTime()) {
			this.setUpdateTime(pattern.getUpdateTime());
		}
		if (null == this.getFileExtension()) {
			this.setFileExtension(pattern.getFileExtension());
		}
		if (null == this.getExistence()) {
			this.setExistence(pattern.getExistence());
		}
		if (null == this.getOwner()) {
			this.setOwner(pattern.getOwner());
		}
		Map<String, String> m = pattern.getAdditionalAttribtues();
		for (Map.Entry<String, String> e : m.entrySet()) {
			if (!this.getAdditionalAttribtues().containsKey(e.getKey())) {
				this.addAdditionalAttribtue(e.getKey(), e.getValue());
			}
		}
		List<PolicyValidator> pvs = pattern.getAdditionalValidators();
		if(pvs != null) {
			for (PolicyValidator pv : pvs) {
				if (!this.getAdditionalValidatorsNames().contains(pv.getName())) {
					this.addAdditionalValidator(pv);
				}
			}
		}
	}

	public String getSystemProperties() {
		return systemProperties;
	}
}
